Advanced Debugging
About AdvDbg Consult Train Services Products Tools Community Contact  
欢迎光临 高端调试 登录 | 注册 | FAQ
 
  ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
 
  格蠹调试套件(GDK)
  格蠹学院
  小朱书店
  老雷的微博
  《软件调试》
  《格蠹汇编》
  《软件调试(第二版)》
沪ICP备11027180号-1

C/C++本地代码调试

帖子发起人: 烈火   发起时间: 2013-04-03 11:45 上午   回复: 2

Print Search
帖子排序:    
   2013-04-03, 11:45 上午
FireBurn 离线,最后访问时间: 2014/2/10 8:02:11 烈火

发帖数前50位
注册: 2013-01-26
发 贴: 28
请教异常捕捉的编译问题
Reply Quote
最近学习《软件调试》24章异处理代码的编译,自己也使用VC6照着书中的例子做实验。

书中提到编译器会使用统一的异常处理函数,同时通过在栈上压入一个范围表的结构来区分不同的异常处理块。
实际实验下来却发现一些不同。

先看一下源代码,使用MFC对话框:
void CTestForOpenEmtyFileDlg::OnOK() 
{
int i = 1;

try
{

Test();
}
catch(CFileException * e)
{
CString strMsg;
e->GetErrorMessage(strMsg.GetBuffer(255),255);
strMsg.ReleaseBuffer();
AfxMessageBox(strMsg);
}
}

void CTestForOpenEmtyFileDlg::Test()
{
CFile file;
//打开不存在的文件
file.Open("1.txt",CFile::modeWrite);
file.Write("ttt",3);
int nLength = file.GetLength();
}

上面通过操作一个不存在的文件来引发CFileException的异常,在OnOK函数中进行捕捉。下面看一下OnOK的汇编代码:
004014d0 55              push    ebp
004014d1 8bec            mov     ebp,esp
004014d3 6aff            push    0FFFFFFFFh
004014d5 68a81b4000      push    offset TestForOpenEmtyFile!AfxWinMain+0x9a (00401ba8)
004014da 64a100000000    mov     eax,dword ptr fs:[00000000h]
004014e0 50              push    eax
004014e1 64892500000000  mov     dword ptr fs:[0],esp
004014e8 83ec0c          sub     esp,0Ch
004014eb 53              push    ebx
004014ec 56              push    esi
004014ed 57              push    edi
004014ee c745fc00000000  mov     dword ptr [ebp-4],0
004014f5 8965f0          mov     dword ptr [ebp-10h],esp
004014f8 e873000000      call    TestForOpenEmtyFile!CTestForOpenEmtyFileDlg::Test (00401570)
004014fd 8b4df4          mov     ecx,dword ptr [ebp-0Ch]
00401500 5f              pop     edi
00401501 5e              pop     esi
00401502 64890d00000000  mov     dword ptr fs:[0],ecx
00401509 5b              pop     ebx
0040150a 8be5            mov     esp,ebp
0040150c 5d              pop     ebp
0040150d c3              ret
0040150e 8d4dec          lea     ecx,[ebp-14h]
00401511 e8d4020000      call    TestForOpenEmtyFile!CString::CString (004017ea)
00401516 8b75e8          mov     esi,dword ptr [ebp-18h]
00401519 6a00            push    0
0040151b 68ff000000      push    0FFh
00401520 68ff000000      push    0FFh
00401525 8b3e            mov     edi,dword ptr [esi]
00401527 8d4dec          lea     ecx,[ebp-14h]
0040152a c645fc02        mov     byte ptr [ebp-4],2
0040152e e8e1020000      call    TestForOpenEmtyFile!CString::GetBuffer (00401814)
00401533 50              push    eax
00401534 8bce            mov     ecx,esi
00401536 ff5714          call    dword ptr [edi+14h]
00401539 6aff            push    0FFFFFFFFh
0040153b 8d4dec          lea     ecx,[ebp-14h]
0040153e e8cb020000      call    TestForOpenEmtyFile!CString::ReleaseBuffer (0040180e)
00401543 8b45ec          mov     eax,dword ptr [ebp-14h]
00401546 6a00            push    0
00401548 6a00            push    0
0040154a 50              push    eax
0040154b e8b8020000      call    TestForOpenEmtyFile!AfxMessageBox (00401808)
00401550 8d4dec          lea     ecx,[ebp-14h]
00401553 c645fc01        mov     byte ptr [ebp-4],1
00401557 e882020000      call    TestForOpenEmtyFile!CString::~CString (004017de)
0040155c b8fd144000      mov     eax,offset TestForOpenEmtyFile!CTestForOpenEmtyFileDlg::OnOK+0x2d (004014fd)
00401561 c3              ret

前面几行进行异常处理函数登记,不过并没有加入范围表scopetable_entry
004014d0 55              push    ebp
004014d1 8bec            mov     ebp,esp
004014d3 6aff            push    0FFFFFFFFh           //tryLevel
004014d5 68a81b4000      push    offset TestForOpenEmtyFile!AfxWinMain+0x9a (00401ba8) //异常处理函数
004014da 64a100000000    mov     eax,dword ptr fs:[00000000h]  //前一个异常登记结构地址
004014e0 50              push    eax
004014e1 64892500000000  mov     dword ptr fs:[0],esp

实际的异常处理模块代码是在地址0040150e,上面登记的是401ba8,又没有范围表进行描述,怎么得到异常处理地址的?

继续看一下那个TestForOpenEmtyFile!AfxWinMain+0x9a (00401ba8) 的汇编代码:
TestForOpenEmtyFile!AfxWinMain+0x9a:
00401ba8 b8d0264000      mov     eax,offset TestForOpenEmtyFile!type_info::`RTTI Complete Object Locator'+0xe0 (004026d0)
00401bad e9c4fcffff      jmp     TestForOpenEmtyFile!_CxxFrameHandler (00401876)

玄机就在第一句,看看4026d0
0:000> dd 4026d0 l5
004026d0  19930520 00000003 00402694 00000001
004026e0  004026bc
继续看一下,004026bc
0:000> dd 4026bc l5
004026bc  00000000 00000000 00000002 00000001
004026cc  004026ac
再看一下,00406ac
0:000> dd 4026ac l4
004026ac  00000000 00403020 ffffffe8 0040150e
实际的异常处理地址40150e赫然在目。

这个结构看来有点复杂。当然事实上我是通过后面的异常分发处理过程的单步跟踪中偶然找到这个值,再一步一步反推上来得到的。
这里简略的提一下,在msvcrt!__CxxExceptionFilter+0x175这里会取到最终的异常处理模块,我就是从这里发现再反推上去。
msvcrt!__CxxExceptionFilter+0x175:
77bf21f2 8b4b0c          mov     ecx,dword ptr [ebx+0Ch] ds:0023:004026b8=0040150e

之后我又在MFC42!AfxCallWndProc这个函数里验证了上面的过程(源代码在WINCORE.cpp中),看来MFC对异常的编译略有不同。

顺便问一句0x19930520这个值出现的频率不低,劳高手请教一下是什么意思。

IP 地址: 已记录   报告
   2013-04-05, 15:41 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: 请教异常捕捉的编译问题
Reply Quote

首先值得注意的是,VC中既支持SEH,又支持C++的异常机制,二者是有很多不同的。写作这一章时,两种异常机制都讨论了,但是因为篇幅太长做删节时,将C++的异常机制删掉了,后来放到了补编电子版中。

http://advdbg.org/books/download/rjts_sup.pdf

因此,建议看一下上面补编内容的P32页。

0x19930520是VC++模拟出的异常结构中的Magic Code,补编中也有介绍(至于这个日期暗示着什么有待考证)。

很好的学习方法,继续坚持探索,就要豁然开朗了^^


IP 地址: 已记录   报告
   2013-04-06, 14:56 下午
FireBurn 离线,最后访问时间: 2014/2/10 8:02:11 烈火

发帖数前50位
注册: 2013-01-26
发 贴: 28
Smile [:)] Re: 请教异常捕捉的编译问题
Reply Quote
感谢张老师的回复。以前看windows核心编程,里面谈到C++异常在其内部是通过结构化异常来实现的,所以一直以为C++异常和SEH内部是完全一致的。当然从程序员使用异常机制的角度来说这么理解也没什么问题。如果这次没有认真的自己也做一遍的话,就不知道内中还有如此区别啊。
IP 地址: 已记录   报告
高端调试 » 软件调试 » C/C++本地代码调试 » 请教异常捕捉的编译问题

 
Legal Notice Privacy Statement Corporate Governance Corporate Governance
(C)2004-2020 ADVDBG.ORG All Rights Reserved.